package client;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Set;
import java.util.UUID;

import common.ClientInterface;
import common.Game;
import common.Level;
import common.Player;
import common.PlayerEvent;
import common.ServerInterface;

public class ClientControllerImpl implements ClientController, ClientInterface {

	private GameWindow view;
	private ServerInterface server;
	private UUID id;
	
	public ClientControllerImpl() {
		
		view = new GameWindow(this);
	}
	
	
//	@Override
//	public void update(String test) {
//		// propagate server updates to view
//		System.out.println("update: " + test);
//	}
	
	@Override
	public void updateGame(Game game) {
		Player[] player = (Player[]) game.getPlayer();
		
//		System.out.println("update Game: " + 
//				(player != null ? player.length : "(null)") + " player" +
//				(game.hasMessage() ? (", message: " + game.getMessage()) : "")
//				);
//		
//		if (player != null)
//			for (Player p : player)
//				System.out.println("  " + (p == null ? "null" : p));
		
		view.setPlayer(player);
		view.setMessage( game.getMessage());
		view.setCoins(game.getCoins());
		view.setScore(player);
		view.setColorChangeCount(game.getColorChangeCount());
		view.updateView();
	}


	@Override
	public void setLevel( int levelNr) {
		view.setLevel(new Level(levelNr));
	}


	public boolean isAttached() {
		return server != null;
	}

	@Override
	public void attachServer(String host, String name) throws RemoteException {
		
		if (isAttached())
			throw new IllegalStateException("already attached to server");
		
		// attach this client to given server
		Registry registry;
		try {
			System.out.println("try to connect to " + host + ":" + Registry.REGISTRY_PORT);
			// get remote RMI registry
			registry = LocateRegistry.getRegistry(host);
			// fetch game server interface object
			server = (ServerInterface) registry.lookup(ServerInterface.RMIName);
			// create client interface object stub from this object
			ClientInterface stub = (ClientInterface) UnicastRemoteObject.exportObject(this, 0);
			// attach to server
			id = server.attachClient(stub, name);
			
		} catch (RemoteException e) {
			server = null;
			id = null;
			throw e;
			
		} catch (NotBoundException e) {
			throw new RemoteException("RMI registry has no '" + ServerInterface.RMIName + "' " +
					"Object bound. Maybe connected to the wrong RMI service?");
		}
	}

	@Override
	public void detachServer() throws RemoteException {
		
		if (!isAttached())
			throw new IllegalStateException("not attached to server");
		
		// detach this client from server
		server.detachClient(id);
		UnicastRemoteObject.unexportObject(this, true);
		server = null;
		id = null;
	}

	@Override
	public void shutdown() {
		
		if (isAttached()) {
			try {
				detachServer();
			} catch (RemoteException e) {
				System.err.println("could not detach from server. Error message: " + 
						e.getLocalizedMessage());
			}
		}
		
		view.shutdownView();
		
	}

	@Override
	public void playerInput(PlayerEvent event) throws RemoteException {

		if (!isAttached())
			throw new IllegalStateException("not attached to server");
		
		// send player events to server
		try {
			server.playerEvent(id, event);
		} catch (RemoteException e) {
			String msg = "could not send playerInput '" + event.name() + "' " +
					"to server. Error message: " + e.getLocalizedMessage();
			System.err.println(msg);
			try {
				detachServer();
			} catch (RemoteException e1) {
				// silently ignore this error...
				server = null;
				id = null;
			}
			throw new RemoteException(msg);
		}
	}


}
